package com.minimalist.basic.config.aspect;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.minimalist.basic.entity.enums.StatusEnum;
import com.minimalist.basic.entity.vo.operatorlog.OperatorLogVO;
import com.minimalist.basic.service.OperatorLogService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

/**
 * @author 11987
 */
@Aspect
@Component
@Slf4j
@AllArgsConstructor
public class LoggingAspect {

    private final OperatorLogService operatorLogService;

    // 定义切点：拦截所有Controller类中的方法
    @Pointcut("execution(* com.minimalist.*.controller..*(..))")
    public void controllerMethods() {
    }

    @Around("controllerMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
                .getRequest();
        OperatorLogVO operatorLogVO = new OperatorLogVO();
        operatorLogVO.setRequestTime(LocalDateTime.now());
        String url = request.getRequestURI();
        String method = request.getMethod();
        if ("GET".equals(method)) {
            return joinPoint.proceed();
        }
        String remoteAddr = request.getRemoteAddr();
        String headers = request.getHeader("User-Agent");
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method proceedMethod = methodSignature.getMethod();
        Operation operation = proceedMethod.getAnnotation(Operation.class);
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        operatorLogVO.setIp(remoteAddr);
        operatorLogVO.setUserAgent(headers);
        operatorLogVO.setExceedTime(String.valueOf(endTime - startTime));
        if (operation != null) {
            operatorLogVO.setName(getOperatorLogName(operation.summary()));
        } else {
            operatorLogVO.setName(getOperatorLogName(method));
        }
        operatorLogVO.setUri(url);
        operatorLogVO.setMethod(method);
        operatorLogVO.setParams(JSON.toJSONString(args));
        String result = JSON.toJSONString(proceed);
        Map<String, String> map = JSON.parseObject(result, new TypeReference<>() {
        });
        if ("200".equals(map.get("statusCodeValue"))) {
            operatorLogVO.setStatus(StatusEnum.STATUS_1.getCode());
        } else {
            operatorLogVO.setStatus(StatusEnum.STATUS_0.getCode());
        }
        operatorLogVO.setResult(result);
        operatorLogService.addOperatorLog(operatorLogVO);
        return proceed;
    }

    private String getOperatorLogName(String summary) {
        if (summary == null || StrUtil.isBlank(summary)) {
            return "";
        }
        if (summary.contains("，")) {
            return summary.split("，")[0];
        } else {
            return summary.split("\\s+")[0];
        }
    }
}
